package com.minidb.cli;

import com.minidb.storage.*;
import com.minidb.utils.Constants;

import java.nio.file.*;
import java.io.IOException;

/**
 * 缓存测试程序
 * 自动测试：
 *   1. 全 miss 场景：访问超过缓存容量的不同页
 *   2. 有命中场景：在缓存容量内重复访问某页
 */
public class CacheTest {

    private static final String DATA_DIR = "./cache_test_data";

    public static void main(String[] args) throws Exception {
        resetDir();

        System.out.println("=== 测试 LRU 策略 ===");
        runTest(Constants.ReplacementPolicy.LRU);

        System.out.println("\n=== 测试 FIFO 策略 ===");
        runTest(Constants.ReplacementPolicy.FIFO);
    }

    private static void runTest(Constants.ReplacementPolicy policy) throws IOException {
        FileManager fm = new FileManager(DATA_DIR);
        BufferPool bp = new BufferPool(3, fm, policy); // 缓存容量 = 3

        String table = "t";
        fm.createTableFile(table);

        // 创建 5 页并写入磁盘
        for (int i = 0; i < 5; i++) {
            Page p = fm.allocatePage(table);
            p.addRecord(java.util.List.of("row_in_page_" + i));
            fm.writePage(table, p);
        }

        /* ===== 场景1: 全 miss ===== */
        System.out.println("\n-- 场景1: 全 miss (访问5个不同的页) --");
        for (int i = 0; i < 5; i++) {
            bp.getPage(table, i); // 都是 miss
        }
        System.out.printf("命中率: %.2f%%%n", bp.getHitRate() * 100);

        /* ===== 场景2: 有命中 ===== */
        System.out.println("\n-- 场景2: 有命中 (缓存内重复访问) --");
        BufferPool bp2 = new BufferPool(3, fm, policy);
        // 放入 3 页
        bp2.getPage(table, 0); // miss
        bp2.getPage(table, 1); // miss
        bp2.getPage(table, 2); // miss

        // 再次访问 page0 → 命中
        bp2.getPage(table, 0); // hit

        // 加入第4页 → 触发淘汰
        bp2.getPage(table, 3); // miss

        System.out.printf("命中率: %.2f%%%n", bp2.getHitRate() * 100);

        bp.flushAll();
        bp2.flushAll();
    }

    private static void resetDir() throws IOException {
        Path root = Path.of(DATA_DIR);
        if (!Files.exists(root)) return;
        try (var s = Files.walk(root)) {
            s.sorted((a,b)->b.getNameCount()-a.getNameCount()).forEach(p -> {
                try { Files.deleteIfExists(p); } catch (IOException ignored) {}
            });
        }
    }
}
